Skip to content

[Lens] Enable monospace numeric font features for Lens renderers#251576

Merged
awahab07 merged 21 commits into
elastic:mainfrom
awahab07:249382_Lens_Activate-monospaced-font-in-charts
Apr 2, 2026
Merged

[Lens] Enable monospace numeric font features for Lens renderers#251576
awahab07 merged 21 commits into
elastic:mainfrom
awahab07:249382_Lens_Activate-monospaced-font-in-charts

Conversation

@awahab07
Copy link
Copy Markdown
Contributor

@awahab07 awahab07 commented Feb 4, 2026

Closes #249382

Summary

Enable monospaced numeric rendering for Lens charts (axis labels, legend values, data labels, tooltips) by introducing a numeric-only font ("Elastic UI Numeric") with the required OpenType features baked into the glyphs, and using it as the first font in the elastic-charts font stack.

An earlier CSS-only approach (font-feature-settings / font-variant-numeric) which works in Chromium/WebKit but is not supported for canvas text in Firefox, has been discarded in favor of the pre-baked "Elastic UI Numeric" font (src/core/packages/apps/server-internal/assets/fonts/elastic_ui_numeric/ElasticUINumeric-Variable.woff2 has all the required numeric features pre-applied). With the new approach, "Elastic UI Numeric" will also work for charts which don't use Inter as the base font e.g. Legacy Metric chart or Tag cloud .

Implementation

  • Added Elastic UI Numeric font (≈8KB WOFF2):
    • Derived from Inter (OFL 1.1), subset to digits + common punctuation via unicode-range
    • Features baked in: tnum, zero, ss01, ss07
  • Registered @font-face globally in core rendering (Fonts template) so Kibana can serve/load it.
  • Prepended 'Elastic UI Numeric' to all elastic-charts fontFamily values in the shared charts ThemeService, ensuring all charts under Lens use it as the preferred font.
  • Applied the same font stack for Lens DOM + tooltip portals (.lnsExpressionRenderer and [id^='echTooltipPortal']) so non-canvas elements/tooltips inherit it too.

Licensing

Elastic UI Numeric is a modified version of Inter licensed under SIL OFL 1.1.

  • OFL text is included in src/core/packages/apps/server-internal/assets/fonts/elastic_ui_numeric/LICENSE.txt
  • We do not use Inter’s Reserved Font Name as the font family name, and the font’s internal naming is updated accordingly.
  • References:

Testing

This dashboard can be used for testing (creds).

Visuals

Lens-charts-and-Elastic_UI_Numeric-font

Before / After

Before After
metric-charts-before Metric-charts-after
line-chart-before line-chart-after
gauge-chart-before gauge-chart-after
pie-chart-before pie-chart-after
table-chart-before table-chart-after

@awahab07 awahab07 requested a review from a team as a code owner February 4, 2026 00:35
@awahab07 awahab07 added release_note:enhancement Team:Visualizations Team label for Lens, elastic-charts, Graph, legacy editors (TSVB, Visualize, Timelion) t// backport:skip This PR does not require backporting labels Feb 4, 2026
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/kibana-visualizations (Team:Visualizations)

@markov00 markov00 requested a review from gvnmagni February 5, 2026 09:29
@gvnmagni
Copy link
Copy Markdown

gvnmagni commented Feb 6, 2026

Thank you @awahab07 for putting this together, it looks amazing!

I noticed a few details which in some cases are directly related to these features and in other cases are a consequence, let me explain.

  • the character 1 (number one) is, for some reason, not in tabular format. In the past this was an issue related to the font file version but with the latest update made by EUI team (https://github.com/elastic/eui-private/issues/463#issuecomment-3513577336) I thought we were fine. I am not sure how to check this since I am not a font expert but as you can see in the image, our number 1 doesn't show that little line at the baseline of the character. Do you know how to check this maybe?
Screenshot 2026-02-06 at 11 50 08
  • I noticed that we could benefit for a smaller letter-spacing (kerning) since monospaced numbers are quite wide. On the design side we would normally set it to -5% but I learned that this might not be the most browser-supported option. How can we reduce it a little bit? I didn't want to set a dimension in pixels since this gets applied to different font-sizes.

There is one additional caveat here, this detail should be applied only when labels are purely numbers because otherwise we would reduce the spacing on letters too. I know this is an additional complexity that probably does not need to be solved here, rather at components side (an example is Metric Chart values, we should introduce this additional css setting directly at the component, not in this PR)
@markov00 CC

Screenshot 2026-02-06 at 11 54 04
  • in Charts Tooltip, and only for the values (data series name are ok) it seems that the feature Open digits (ss01) does not get applied. Number are still the original Inter version
Screenshot 2026-02-06 at 11 58 23
  • Last thing but probably the most important, you already mentioned this Abdul, the monospaced features have affected the size of numbers and therefore all calculations about string length are affected by this.
    We can notice it in Metric Chart, in treemap labels where either number gets cut off or labels get too close to each other. Probably axis are affected too but we don't noticed since they are very small.
    @markov00 tagging you just to check how to proceed in this case (please read also previous comment about letter-spacing which is related
Screenshot 2026-02-06 at 11 37 39 Screenshot 2026-02-06 at 11 37 50

Happy to talk about these in person if that is easier, thank you again Abdul!

@markov00
Copy link
Copy Markdown
Contributor

markov00 commented Feb 6, 2026

@awahab07 @gvnmagni about:

Last thing but probably the most important, you already mentioned this Abdul, the monospaced features have affected the size of numbers and therefore all calculations about string length are affected by this.
We can notice it in Metric Chart, in treemap labels where either number gets cut off or labels get too close to each other. Probably axis are affected too but we don't noticed since they are very small.
@markov00 tagging you just to check how to proceed in this case (please read also previous comment about letter-spacing which is related
Screenshot 2026-02-06 at 11 37 39 Screenshot 2026-02-06 at 11 37 50

This happens because the canvas used to compute the text width in Charts doesn't have the same font variables applied. Thus the calculation consider just the classic Inter font config and sizes.
We can alleviate this by:

  1. verify if we can optionally apply the same font variables within the elastic-charts library
  2. or we can change the way the text width calculation works and instead of using a offscreen canvas, it uses an empty but existing html canvas on the dom hierarchy of the elastic charts library. you can just add a canvas there and reuse it instead of the using withTextMeasure (that creates a empty canvas) the withTextMeasure could always pick up an existing dom canvas element, inheriting the font variables.

@gvnmagni
Copy link
Copy Markdown

@tkajtoch sorry to bother, can we ask you one thing? do you maybe know something about the first point of my message above? For some reason the number 1 digit does not get monospaced features applied. We had the same issue when we tested together and it got solved by the update of font version, and actually in your EUI pr it works fine

I can't figure it out and I figured it might have worth to ask before going into a rabbit hole :)

@awahab07 awahab07 changed the title [Lens] Enable monospace numeric font features for Lens renderers WIP - [Lens] Enable monospace numeric font features for Lens renderers Feb 16, 2026
@awahab07
Copy link
Copy Markdown
Contributor Author

@elasticmachine merge upstream

@awahab07 awahab07 marked this pull request as draft February 26, 2026 12:33
@awahab07
Copy link
Copy Markdown
Contributor Author

awahab07 commented Mar 1, 2026

image

This issue is now fixed so the chart tooltips are now shown like:

image

@awahab07
Copy link
Copy Markdown
Contributor Author

awahab07 commented Mar 1, 2026

@gvnmagni @tkajtoch

@tkajtoch sorry to bother, can we ask you one thing? do you maybe know something about the first point of my message above? For some reason the number 1 digit does not get monospaced features applied. We had the same issue when we tested together and it got solved by the update of font version, and actually in your EUI pr it works fine

I can't figure it out and I figured it might have worth to ask before going into a rabbit hole :)

Inter v3, which is currently used by Kibana (specifically Version 3.018), doesn't have
font-feature-settings: "cv01"
settings available for digit 1. Inter v4 does have it (Ideally we should upgrade to v4.1). The latest on v3 is v3.19, which also doesn't have that bottom base for digit 1. See Inter font releases here.

In order to inspect available font features, drag the file onto https://wakamaifondue.com/beta/ and it'll show available font features
image
clicking the the feature will show what glyphs it supports, e.g. clicking cv01 for v3 vs. v4

v3v4
image image
image image

For visual difference when upgrading to v4 from v3, font author says:

Even though the UPM (the font's coordinate system) has changed along with metrics, I've done my best to make sure existing uses of Inter version 3 will look as close to identical as possible for small text sizes, in particular run length.

However you should expect to see noticeable differences when switching to Inter version 4.

See how do we want to proceed here.

@awahab07
Copy link
Copy Markdown
Contributor Author

awahab07 commented Mar 2, 2026

About the issue mentioned above:
image

There's PR elastic/elastic-charts#2798 which uses in-Dom Canvas (instead of off-screen Canvas) to measure text. This works quite well, but discovered a limitation that Canvas element in Firefox does not support OpenType Font Features like font-feature-settings and font-variant-numeric.

@gvnmagni
Copy link
Copy Markdown

gvnmagni commented Mar 4, 2026

thanks @awahab07, two points here:

1 - Version 4 of Inter font. @markov00 reached out to EUI again since they had a PR for this, they re-opemn it (#242012) and we can probably review and approve it. It should fix all these issues and it would be awesome

2 - Firefox bug. I am afraid we can't avoid it, Marco was suggesting a little trick, to add a few pixel to the calculation. If the math return us a value of 100px of length, let's by default add a few pixels in order for that to fix the problem with a little hack. I hope I explained that properly, we can discuss it together with Marco as well maybe so that we evaluate that

@awahab07
Copy link
Copy Markdown
Contributor Author

I’ve filed a bug with Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=2024179. If it gets fixed on their side, that would be ideal and we can avoid introducing any workarounds.

@awahab07
Copy link
Copy Markdown
Contributor Author

The WHATWG's Canvas Text Propagation Algorithm doesn't mention propagating OpenType font features, and as a result Firefox doesn't implement it (and may not implement unless it's part of the standard).

There's a WHATWG discussion about enabling OpenType font features for Canvas (explicit way of defining font attributes for Canvas), but doesn't seem like it'll be dealt with anytime soon.

This is a major blocker, that on Firefox, all Canvas based charts cannot render OpenType font features.

@awahab07 awahab07 added the ci:cloud-deploy Create or update a Cloud deployment label Mar 26, 2026
@awahab07 awahab07 added the ci:cloud-deploy Create or update a Cloud deployment label Mar 31, 2026
@elastic elastic deleted a comment from kibanamachine Mar 31, 2026
@kibanamachine
Copy link
Copy Markdown
Contributor

Cloud deployment initiated, see credentials at: https://buildkite.com/elastic/kibana-deploy-cloud-from-pr/builds/896

@awahab07 awahab07 removed the ci:cloud-persist-deployment Persist cloud deployment indefinitely label Apr 1, 2026
@awahab07 awahab07 changed the title WIP - [Lens] Enable monospace numeric font features for Lens renderers [Lens] Enable monospace numeric font features for Lens renderers Apr 1, 2026
@awahab07 awahab07 marked this pull request as ready for review April 1, 2026 01:16
@awahab07 awahab07 requested a review from a team as a code owner April 1, 2026 01:16

it('should render tagcloud', async () => {
const tags = await tagCloud.getTextTag();
expect(tags).to.eql([
Copy link
Copy Markdown
Contributor Author

@awahab07 awahab07 Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an expected regression as with font update, rendered tags now diff in count and order.

BeforeAfter
Image Image

'RangeKey no label auto assigned - Tag Cloud'
);

expect(seriesColors).to.eql([
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See

@elasticmachine
Copy link
Copy Markdown
Contributor

elasticmachine commented Apr 2, 2026

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #94 / serverless search UI Rule details Edit rule with deleted connector should show and update deleted connectors when there are existing connectors of the same type

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
charts 165 166 +1

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
expressionLegacyMetricVis 6.3KB 6.4KB +148.0B
expressionTagcloud 18.1KB 18.2KB +24.0B
lens 2.0MB 2.0MB +286.0B
total +458.0B

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
charts 37.2KB 37.4KB +179.0B

History

Copy link
Copy Markdown
Contributor

@markov00 markov00 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested locally, looks great!

@awahab07 awahab07 enabled auto-merge (squash) April 2, 2026 08:51
Copy link
Copy Markdown
Contributor

@jloleysens jloleysens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work @awahab07 ! I've left a comment regarding tests, otherwise code-only review from core lgtm.

unicode-range: ${unicodeRange};`
: ''
}
${fontFaceRules.join('\n ')}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little surprised there's no test case for this yet... would you mind adding one? Thank you!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out @jloleysens, I've opened a PR #262103.

@awahab07 awahab07 merged commit 6ba2bc1 into elastic:main Apr 2, 2026
18 checks passed
paulinashakirova pushed a commit to paulinashakirova/kibana that referenced this pull request Apr 2, 2026
…stic#251576)

Closes elastic#249382

## Summary

Enable monospaced numeric rendering for Lens charts (axis labels, legend
values, data labels, tooltips) by introducing a **numeric-only font**
(`"Elastic UI Numeric"`) with the required OpenType features **baked
into the glyphs**, and using it as the **first font in the
elastic-charts font stack**.

An earlier CSS-only approach (`font-feature-settings` /
`font-variant-numeric`) which works in Chromium/WebKit but is **not
supported for canvas text in Firefox**, has been discarded in favor of
the pre-baked `"Elastic UI Numeric"` font
(`src/core/packages/apps/server-internal/assets/fonts/elastic_ui_numeric/ElasticUINumeric-Variable.woff2`
has all the required numeric features pre-applied). With the new
approach, `"Elastic UI Numeric"` will also work for charts which don't
use Inter as the base font e.g. **Legacy Metric** chart or **Tag cloud**
.

## Implementation

- **Added `Elastic UI Numeric` font (≈8KB WOFF2)**:
- Derived from Inter (OFL 1.1), **subset to digits + common
punctuation** via `unicode-range`
  - Features baked in: **`tnum`, `zero`, `ss01`, `ss07`**
- **Registered `@font-face` globally** in core rendering (`Fonts`
template) so Kibana can serve/load it.
- **Prepended `'Elastic UI Numeric'` to all elastic-charts `fontFamily`
values** in the shared charts `ThemeService`, ensuring all charts under
Lens use it as the preferred font.
- **Applied the same font stack for Lens DOM + tooltip portals**
(`.lnsExpressionRenderer` and `[id^='echTooltipPortal']`) so non-canvas
elements/tooltips inherit it too.

## Licensing

`Elastic UI Numeric` is a **modified version of Inter** licensed under
**SIL OFL 1.1**.
- OFL text is included in
`src/core/packages/apps/server-internal/assets/fonts/elastic_ui_numeric/LICENSE.txt`
- We do **not** use Inter’s Reserved Font Name as the font family name,
and the font’s internal naming is updated accordingly.
- References:
- Upstream OFL text: [Inter
LICENSE.txt](https://raw.githubusercontent.com/rsms/inter/master/LICENSE.txt)
- Google Fonts page (also OFL): [Inter
license](https://fonts.google.com/specimen/Inter/license)

## Testing

This
[dashboard](https://kibana-pr-251576-16eb8c.kb.us-west2.gcp.elastic-cloud.com/app/dashboards#/view/43090e2b-ba4e-4c1e-94a9-18e9c97295f4)
can be used for testing
([creds](elastic#251576 (comment))).

## Visuals

<img width="2400" height="7200"
alt="Lens-charts-and-Elastic_UI_Numeric-font"
src="https://github.com/user-attachments/assets/4cc07dd3-6d45-468d-af04-156f7be5966f"
/>

<details>

<summary>
 <h4>Before / After</h4>
</summary>

| Before | After |
|--------|-------|
| <img width="400" alt="metric-charts-before"
src="https://github.com/user-attachments/assets/33d547f0-b8f0-42fd-a37b-7ef20a5d05ee"
/> | <img width="400" alt="Metric-charts-after"
src="https://github.com/user-attachments/assets/0d6e3738-14db-4eb7-af77-5717bdcc1377"
/> |
| <img width="400" alt="line-chart-before"
src="https://github.com/user-attachments/assets/e9abac31-5050-47ba-8f0e-fabd663de378"
/> | <img width="400" alt="line-chart-after"
src="https://github.com/user-attachments/assets/0e8bd3ab-17ee-4f4a-9824-b4bb33ff7486"
/> |
| <img width="400" alt="gauge-chart-before"
src="https://github.com/user-attachments/assets/9b74f30e-0e3e-42cf-95af-a1db10365b56"
/> | <img width="400" alt="gauge-chart-after"
src="https://github.com/user-attachments/assets/cdf2dd48-6a28-4422-bcfd-114ba0014834"
/> |
| <img width="400" alt="pie-chart-before"
src="https://github.com/user-attachments/assets/f6ff8d44-d4ff-4bb0-b4df-28c654a65f4d"
/> | <img width="400" alt="pie-chart-after"
src="https://github.com/user-attachments/assets/48e34805-cc50-40c0-97fa-654c82c4f74a"
/> |
| <img width="400" alt="table-chart-before"
src="https://github.com/user-attachments/assets/445eb6e5-8bad-4cb7-9b66-e20fd522a107"
/> | <img width="400" alt="table-chart-after"
src="https://github.com/user-attachments/assets/2dffd504-b4d3-4cd9-8994-1f2422c3426b"
/> |

</details>

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
awahab07 added a commit that referenced this pull request Apr 7, 2026
…als outside of Lens (#261168)

## Summary

Fix issue where `"Elastic UI Numeric"` font is applied to portals
outside of Lens e.g. fields overview popover in Discover or Datepicker
popover. (The monospaced font `"Elastic UI Numeric"` is added in
#251576)

Before

<img width="1237" height="997" alt="image"
src="https://github.com/user-attachments/assets/0f140778-44fe-4644-ab3d-e19e71507c69"
/>


After

<img width="1239" height="997" alt="image"
src="https://github.com/user-attachments/assets/256f4288-aa7d-4809-b623-bc1cae464c2f"
/>
benakansara added a commit that referenced this pull request Apr 7, 2026
…I theme context (#261476)

Resolves #260954

### Summary

- Fixes `Cannot read properties of undefined (reading 'font')` error
when rendering the Lens chart in the alerting_v2 rule preview
- Wraps both app mount functions with `coreStart.rendering.addContext()`
to provide the EUI theme (and other Kibana global context) to the React
tree

### Root Cause

The alerting_v2 app mounts via ReactDOM.render() which creates a
standalone React tree without any EUI ThemeProvider. When Lens renders
its embeddable chart inside the rule preview, `lnsNumericFontStyles`
reads `euiTheme.font.family` (PR:
#251576) from Emotion's theme
context which is undefined without the provider, causing the error.

### Testing

- Open alerting_v2 rule form and trigger a rule preview with an ES|QL
query that renders a Lens chart
- Verify the chart renders without errors
- Verify notification policies page still loads correctly

### Screenshots

<img width="1234" height="781" alt="Screenshot 2026-04-07 at 10 21
24 AM"
src="https://github.com/user-attachments/assets/9375415e-8aae-493a-b8c3-006db48333ca"
/>
kelvtanv pushed a commit to kelvtanv/kibana that referenced this pull request Apr 7, 2026
…als outside of Lens (elastic#261168)

## Summary

Fix issue where `"Elastic UI Numeric"` font is applied to portals
outside of Lens e.g. fields overview popover in Discover or Datepicker
popover. (The monospaced font `"Elastic UI Numeric"` is added in
elastic#251576)

Before

<img width="1237" height="997" alt="image"
src="https://github.com/user-attachments/assets/0f140778-44fe-4644-ab3d-e19e71507c69"
/>


After

<img width="1239" height="997" alt="image"
src="https://github.com/user-attachments/assets/256f4288-aa7d-4809-b623-bc1cae464c2f"
/>
kelvtanv pushed a commit to kelvtanv/kibana that referenced this pull request Apr 7, 2026
…I theme context (elastic#261476)

Resolves elastic#260954

### Summary

- Fixes `Cannot read properties of undefined (reading 'font')` error
when rendering the Lens chart in the alerting_v2 rule preview
- Wraps both app mount functions with `coreStart.rendering.addContext()`
to provide the EUI theme (and other Kibana global context) to the React
tree

### Root Cause

The alerting_v2 app mounts via ReactDOM.render() which creates a
standalone React tree without any EUI ThemeProvider. When Lens renders
its embeddable chart inside the rule preview, `lnsNumericFontStyles`
reads `euiTheme.font.family` (PR:
elastic#251576) from Emotion's theme
context which is undefined without the provider, causing the error.

### Testing

- Open alerting_v2 rule form and trigger a rule preview with an ES|QL
query that renders a Lens chart
- Verify the chart renders without errors
- Verify notification policies page still loads correctly

### Screenshots

<img width="1234" height="781" alt="Screenshot 2026-04-07 at 10 21
24 AM"
src="https://github.com/user-attachments/assets/9375415e-8aae-493a-b8c3-006db48333ca"
/>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting ci:cloud-deploy Create or update a Cloud deployment release_note:enhancement Team:Visualizations Team label for Lens, elastic-charts, Graph, legacy editors (TSVB, Visualize, Timelion) t// v9.4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Lens] Activate monospaced font in charts

6 participants